/*
 * This file is part of LangMan.
 *
 * LangMan is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * LangMan is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with LangMan.  If not, see <http://www.gnu.org/licenses/>.
 */

package langman.util.async;

import javafx.beans.property.*;
import javafx.concurrent.WorkerStateEvent;
import javafx.event.EventHandler;
import langman.util.doping.SingletonBean;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

@SingletonBean
public class TaskExecutorService implements EventHandler<WorkerStateEvent> {
    private final Executor        executor   = Executors.newSingleThreadExecutor();
    private final BooleanProperty running    = new SimpleBooleanProperty(this, "running");
    private final DoubleProperty  progress   = new SimpleDoubleProperty(this, "progress");
    private final StringProperty  status     = new SimpleStringProperty(this, "status");
    private final StringProperty  actionName = new SimpleStringProperty(this, "actionName");
    private final BooleanProperty stopping   = new SimpleBooleanProperty(this, "stopping");
    private final Logger          logger     = LogManager.getLogger(getClass());

    private StatusTask<?> taskInExecution;

    public BooleanProperty stoppingProperty() {
        return stopping;
    }

    public StringProperty statusProperty() {
        return status;
    }

    public StringProperty actionNameProperty() {
        return actionName;
    }

    public void execute(String actionName, StatusTask<?> task) {
        taskInExecution = task;

        if (task == null || task.isRunning()) {
            return;
        }

        this.actionName.set(actionName);

        running.bind(task.runningProperty());
        progress.bind(task.progressProperty());
        status.bind(task.statusProperty());

        task.addEventHandler(WorkerStateEvent.ANY, this);

        stopping.set(false);
        executor.execute(task);
    }

    public ReadOnlyBooleanProperty runningProperty() {
        return running;
    }

    public DoubleProperty progressProperty() {
        return progress;
    }

    public void stopTask() {
        if (taskInExecution != null && taskInExecution.isRunning()) {
            stopping.set(true);
            taskInExecution.cancel(true);
        }
    }

    @Override
    public void handle(WorkerStateEvent workerStateEvent) {
        if (workerStateEvent.getEventType().equals(WorkerStateEvent.WORKER_STATE_FAILED)) {
            Throwable exception = workerStateEvent.getSource().getException();
            if (exception != null) {
                logger.error(exception.getMessage(), exception);
            }
        }
    }
}
